import java.util.concurrent.Semaphore;

class IntConsumer{
    public void accept(int num){
        System.out.println(num);
    }
}


public class ZeroEvenOdd {
    private int n;

    private int num;

    private Semaphore semOdd,semEven,semZero;

    public ZeroEvenOdd(int n) {
        this.n = n;
        this.num=1;
        this.semZero=new Semaphore(1);
        this.semOdd=new Semaphore(0);
        this.semEven=new Semaphore(0);
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            semZero.acquire();
            printNumber.accept(0);
            if (num % 2 == 1) {
                semOdd.release();
            } else {
                semEven.release();
            }
        }
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        int time=n/2;
        for (int i=0; i<time;i++){
            semEven.acquire();
            printNumber.accept(num);
            num++;
            semZero.release();
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        int time=n/2+n%2;
        for (int i=0; i<time;i++){
            semOdd.acquire();
            printNumber.accept(num);
            num++;
            semZero.release();
        }
    }

    public static void main(String[] args) {
        ZeroEvenOdd test=new ZeroEvenOdd(45);
        IntConsumer consumer=new IntConsumer();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    test.even(consumer);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    test.zero(consumer);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    test.odd(consumer);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
